#ifndef RENDERPROCESS_H
#define RENDERPROCESS_H

#include <QtGui>
#include <QMutex>
#include <QThread>
#include <QWaitCondition>

#include "glewinitialisation.h"
#include <QGLViewer/qglviewer.h>
using namespace qglviewer;

#include "volume.h"

#if defined (__APPLE__) || defined(MACOSX)
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include "boundingbox.h"
#include "lightinginformation.h"
#include "screenbox.h"

class RenderProcess : public QObject
{
  Q_OBJECT

 public :
  RenderProcess(QObject *parent = 0);
  ~RenderProcess();

  void setViewer(QGLViewer *);
  void setLogger(QTextEdit *);

  void setTextureSize(int);
  void setMemorySize(int);
  void setScale(Vec);
  Vec scale();
  void setStep(float);
  void setRaycaster(int);
  void toggleShadows();

  void toggleSurfaceType();
  void setSurfaceType(bool);
  void setSurfaceColor(Vec);
  Vec surfaceColor();

  void setLodLevel(int);
  void setUserLodLevel(int, bool);
  void toggleBestLodAlways(bool);

  void setDepthcue(bool);
  void setHilights(bool);

  void setUserLimits(int, float, float);

  void loadVolume(QList<QString>);

  void setWindowSize(int, int);
  void setGridsize(int, int, int);

  float* getLUT();
  void setLUT(float*);
  void setLUT(QList<QImage>);

  void setIsovalue(int);
  void setMaxBlocks(int);

  void stopRender();

  void gridSize(int&, int&, int&);

  void togglePaintUsingScreenBox();
  void toggleLight();
  void toggleIntermediate();
  void toggleDepthcue();
  void toggleBounds();
  void toggleBox();
  void toggleOuterBox();
  LightingInformation lightInfo();

  bool screenBoxGrabsMouse();
  bool screenBoxKeyPressEvent(QKeyEvent*);

  QImage histogramImage1D();
  QImage histogramImage2D();

  void changeTimestep(int);
  void setBoxSize(Vec);
  void setBoxSize(int);

  void updateLookFrom(Vec, Quaternion);

  Vec boxSize4D();
  void set4DboxSize(Vec);

  void bounds(Vec&, Vec&);
  void setBounds(Vec, Vec);

  int timeStep();
  void setTimeStep(int, bool flag=true);
  void setInterpolateValues(float);
  void setInterpolateValues(bool);

 signals :
  void switchOffAutoBufferSwapping();
  void startDraw();
  void runPart1();
  void part1Done(bool);
  void loadBlocks(QList<Vec>, int);
  void loadAllValidBlocks(int);
  void renderDone();

 public slots :
  void setShowBufferOnly(bool);
  void toggleShowBufferOnly();
  void startRender();  
  void fastRender();  
  void draw();
  void part1();
  void loopPart1(bool);
  void nextLot();
  void updateBounds();

  void setLightInfo(LightingInformation);
  void updateLightVector(Vec);
  void applyLighting(bool);
  void applyEmissive(bool);
  void applyShadows(bool);
  void updateHighlights(Highlights);
  void updateShadowBlur(float);
  void updateShadowScale(float);
  void updateShadowFOV(float);
  void updateShadowIntensity(float);

  void saveImageToClipboard();
  void saveImage();
  QImage getImage();

  void changeStep(int);

  void addScreenBox();

 private :
  QGLViewer *m_viewer;
  Volume *m_volume;
  QTextEdit *m_log;
  QString m_shaderDir;

  bool m_showBufferOnly;
  bool m_allValidBlocks;

  int m_nVolumes;

  Vec m_prevPos;
  Quaternion m_prevRot;

  bool m_userLodChanged;
  bool m_userLod;
  bool m_userLodSticky;
  bool m_bestLodAlways;
  bool m_bestLodAlwaysSticky;
  int m_lodUser;
  int m_lodCurrent;
  int m_lodMin;
  int m_volLodMin;

  int m_od, m_or, m_oc;
  int m_d, m_r, m_c;
  int m_bd, m_br, m_bc;
  int m_cd, m_cr, m_cc;
  int m_nblocks;

  Vec m_4DboxSize;
  bool m_mixvol;
  float m_interpVol;

  uchar *m_blockLevels;
  
  int m_bsz;
  float m_tstep;

  int m_maxBlocks;
  int m_isoval;
  bool m_showIntermediate;
  bool m_veryFirstRun;
  bool m_nextBlocks;

  Vec m_boxMinUser, m_boxMaxUser;
  Vec m_origVolDim, m_volDim;
  uint m_windowWidth, m_windowHeight;

  bool m_recreateShader;
  bool m_resize;
  int m_w, m_h;

  bool m_renderState;
  bool m_updateBlockLevels;
  bool m_doRender, m_fastRender;
  bool m_interrupt;
  QWaitCondition m_condition;
  QMutex m_mutex;

  GLuint m_dataTex;
  GLuint m_auxTex;
  GLuint m_levelTex;
  GLuint m_lutTex;

  GLuint m_posBuffer;
  GLuint m_posTex[2];
  GLuint m_rayTex[2];
  GLuint m_colTex[2];

  GLhandleARB m_geoShader;
  GLint m_geoparm[50];

  GLhandleARB m_RCShader;
  GLint m_RCparm[50];

  GLhandleARB m_FBShader;
  GLint m_FBparm[50];

  GLhandleARB m_lightShader;
  GLint m_lightparm[50];

  GLhandleARB m_splatShader;
  GLint m_splatparm[50];
  
  GLhandleARB m_smoothShader;
  GLint m_smoothparm[50];

  int m_cpa, m_cpb;
  float *m_posArray;

  int m_raycasterType;
  bool m_surfaceType;
  Vec m_surfaceColor;
  bool m_depthcue;
  Vec m_scale;
  Vec m_userScale;

  QList<qint64> m_prevKeys;
  uchar *m_screenDump;

  uchar *m_lut;
  float *m_olut;

  float *m_tmpArray;

  bool m_showBox, m_showOuterBox;
  bool m_showBoundingBox;
  BoundingBox m_boundingBox;
  LightingInformation m_lightInfo;

  bool m_paintUsingScreenBox;
  bool m_screenBoxActive;
  int m_currScreenBox;
  int m_lowresBufferId;

  ScreenBox *m_screenBox;

  void processLUT();

  void runByParts();

  void drawBox();
  void drawEnclosingBox(Vec, Vec);

  void updateBlockLevels();

  void initPBO();
  void resize();

  void createRaycastShader();
  void createRaycastShader(QString);
  void createFindBlocksShader(QString);
  void createLightShader(QString);
  void createSmoothShader(QString);
  void createSplatShader(QString);
  void createGeometryShader(QString);
  bool loadShader(GLhandleARB&, QString);

  void raycast();
  void findBlocks();

  void loadBlockLevels();
  bool loadAuxDataTextures();
  void enableTextureUnits();
  void disableTextureUnits();

  void bindBuffer(int);
  void releaseBuffer();
  void showBuffer(int, bool, bool);
  void smoothBuffer();
  void splatBuffer(int);

  void depthcueLimits(float&, float&);

  void genBlockMap();

  void drawScreenQuad(float, float, float, float);
  void showLodLevel();

  int finestLod();

  bool checkRedraw();
  bool checkLodChange(bool);

  void getScreenDump();

  void genSAT(int);
};


#endif
